﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Threading;
using Fadd.Collections;

namespace Fadd.Net
{
    /// <summary>
    /// Hosts channels.
    /// </summary>
    public class RemoteChannelServer : IStartable, IRemoteChannel
    {
        private SimpleServer _server;
        private List<BinaryTransport<RemoteChannelPacket>> _clients = new List<BinaryTransport<RemoteChannelPacket>>();
        private readonly GenericSubscriberList _subscribers;
        [ThreadStatic] private static BinaryTransport<RemoteChannelPacket> _current;


        public RemoteChannelServer(IPEndPoint endPoint)
        {
            _server= new SimpleServer(endPoint, OnClientAccepted);
        }

        private void OnClientAccepted(Socket socket)
        {
            var client = new BinaryTransport<RemoteChannelPacket>(socket);
            client.ObjectReceived += OnObject;
            client.Start();
            _clients.Add(client);
        }

        private void OnObject(object sender, ObjectEventArgs<RemoteChannelPacket> e)
        {
            _current = (BinaryTransport<RemoteChannelPacket>)sender;
            _subscribers.Invoke(e.Object);
        }


        /// <summary>
        /// Start component
        /// </summary>
        public void Start()
        {
            _server.Start(5);
        }

        /// <summary>
        /// Stop component
        /// </summary>
        public void Stop()
        {
            _server.Stop();

        }


        /// <summary>
        /// Register handler for an object
        /// </summary>
        /// <typeparam name="T">Type of object to receive.</typeparam>
        /// <param name="consumer">Implementation to invoke when object is received.</param>
        public void Register<T>(IRemoteObjectConsumer<T> consumer)
        {
            _subscribers.Register<T>(consumer);
        }

        /// <summary>
        /// Send an object
        /// </summary>
        /// <param name="value">Object to send, must implement <see cref="ISerializable"/>.</param>
        /// <remarks>
        /// Only work 
        /// </remarks>
        public void Send(object value)
        {
                _current.Send(new RemoteChannelPacket(value));
        }
    }
}
